/* arch/x86/include/arch/arch_task.h 
 * 
 * Copyright (C) 2021, 2022 intirain. 
 *
 * This file is part of evx. 
 * 
 * evx is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * evx is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with evx. If not, see <https://www.gnu.org/licenses/>
 */ 




#ifndef __ARCH_TASK_H
#define __ARCH_TASK_H

#include <kernel/task.h>
#include <arch/archinfo.h>
#include <arch/int.h>
#include <arch/string.h>

#ifndef __ASSEMBLER__

extern void ret_intr(void);
extern void die(void);

/* it's crazy */
#define STACK_SIZE 		512

struct arch_task_descr {
	/* current stack pointer */
	__archptr_t 		sp;
	/* page table base */
	__archptr_t 		ptable;
	/* segment selector, data */
	__archptr_t 		sel;
};

#define ARCH_TASK_DESCR_INIT { \
	.sp = 0, \
	.ptable = 0, \
	.sel = 0x08 \
}

static inline struct arch_task_descr *arch_task_descr_init(struct arch_task_descr *p) {
	p->sp = 0;
	p->ptable = 0;
	p->sel = 0x08;

	return p;
}


static inline int arch_stack_init(struct arch_task_descr *p) {
	struct registers *regs;

	if (unlikely(!(p->sp = (__archptr_t) early_kmalloc(STACK_SIZE, 1)))) 
		panic("arch_stack_init: Out of memory");

	p->sp += STACK_SIZE;

	regs = (struct registers *) ((void *) p->sp - sizeof(struct registers));
	memset(regs, 0, sizeof(struct registers));

	regs->gs = regs->fs = regs->es = regs->ds = 0x10;
	regs->ip = (__archptr_t) die;
	regs->cs = 0x08;
	regs->flags = 0x20;
	regs->sp = p->sp;
	regs->ss = 0x10;

	return 0;
}

/* it's not so easy to understand this. we just pop the registers in the stack 
 * and return. for the first time, the ip (in stack but not in a structure) is 
 * ret_intr */

#define switch_to(task) ({ 				\
	__asm__ volatile ( 				\
		"movq %%rsp, %0\n\t" 			\
		"movq %1, %%rsp\n\t" 			\
		"jmp ret_intr\n\t" 			\
		: "=m" (current->arch_descr.sp) 	\
		: "m" (task->arch_descr.sp) 		\
	);						\
})


#endif
#endif


